home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Suntar 1.3.2 / mainEvent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-18  |  35.0 KB  |  1,246 lines  |  [TEXT/KAHL]

  1. /* this file contains code from two TextEdit-based little editors: */
  2.  
  3. /*********************************************************************
  4.  
  5.     MiniEdit.c
  6.  
  7.     The sample application from Inside Macintosh (RoadMap p.
  8.     15-17)
  9.     beefed up a bit by Stephen Z. Stein, Symantec Corp.
  10.  
  11. *********************************************************************/
  12. /*------------------------------------------------------------------------------
  13. #
  14. #    Apple Macintosh Developer Technical Support
  15. #
  16. #    MultiFinder-Aware TextEdit Sample Application
  17. #
  18. #    TESample.c
  19. #
  20. #    Copyright © 1989 Apple Computer, Inc.
  21. #    All rights reserved.
  22. #
  23. ------------------------------------------------------------------------------*/
  24.  
  25. /* the integration of the two environments (MiniEdit is autowrap-only, TESample
  26. is horizontal scroll only, both are single-window and their programming style is 
  27. often radically different) is by us: */
  28.  
  29. /*******************************************************************************\
  30.  
  31. main events module
  32.  
  33. suntar, ©1991-92 Sauro & Gabriele Speranza
  34.  
  35. This program is public domain, feel free to use it or part of it for anything
  36.  
  37. \*******************************************************************************/
  38.  
  39. /* In general, we have kept the general structure of MiniEdit (which is easier to
  40. understand) but inserting many small excerpts of code from TESample (which is more
  41. powerful: for example, it's MultiFinder aware). Many features, however, are
  42. completely new for suntar and come from neither MiniEdit nor TESample.
  43. */
  44.  
  45. #include "antiglue.h"
  46. #include "system7.h"
  47.  
  48. /* inutili, sono in MacHeaders
  49. #include <QuickDraw.h>
  50. #include <MacTypes.h>
  51. #include <FontMgr.h>
  52. #include <WindowMgr.h>
  53. #include <MenuMgr.h>
  54. #include <TextEdit.h>
  55. #include <DialogMgr.h>
  56. #include <EventMgr.h>
  57. #include <DeskMgr.h>
  58. #include <FileMgr.h>
  59. #include <ToolboxUtil.h>
  60. #include <ControlMgr.h>
  61. */
  62.  
  63.  
  64. #include "windows.h"
  65. #include "suntar.h"
  66.  
  67. #define REQUIREDSTACK 16384
  68.  
  69. void (*my_add_menus)(void) =NULL;    /* aggiunta menù dopo il menù preferences 
  70.                                     --add items in the preferences menu and further menus
  71.                                     */
  72. void (*my_handle_menus)(long)=NULL;        /* gestione nuove entry in qualunque menù 
  73.                                     -- handles selection of any application-installed menu item
  74.                                     */
  75. void (*my_event_filter)(EventRecord*)=NULL;    /* permette di "filtrare" un evento, dopo che
  76.                 MainEvent ha chiamato GetNextEvent e prima che lo
  77.                 gestisca, basta settare il campo what a nullEvent per 
  78.                 sopprimere la gestione standard
  79.                 -- event filter !
  80.                 */
  81. short (*my_at_exit)(void);        /* azioni da compiere al Quit 
  82.                                 --quit handler
  83.                                 */
  84.  
  85. static short quit_selection;
  86. static short n_about_entries;
  87. unsigned char PNS[]="\p";
  88. Point badmount_point={80,112};
  89.  
  90. window_def        my_windows[n_max_windows];    /* si potrebbe anche renderla una lista
  91.                                             per non avere un valore massimo... ma mi fa comodo
  92.                                             così per decidere dove posizionare le finestre */
  93. short            n_currently_open=0;
  94. window_def        *curr_window=NULL;    /* la finestra attualmente corrente 
  95.                                     -- if the currently active window belongs to this module,
  96.                                     curr_window must point to it (and the current grafport
  97.                                     is set to it)
  98.                                     */
  99. TEHandle        TEH;            /* della finestra corrente...
  100.                                 -- copy of curr_window->TEH */
  101.  
  102. static WindowPtr foreign_window[n_max_foreign];
  103. static upd_proc update_handler[n_max_foreign],activate_handler[n_max_foreign];
  104.  
  105. MenuHandle        myMenus[4];
  106. MenuHandle        fontM[3];
  107. #ifdef SUNTAR
  108. MenuHandle        hqxM;
  109. #endif
  110. Cursor            editCursor;
  111. Cursor            waitCursor;
  112. static struct acur{
  113.     short n_cursors;
  114.     short delay;
  115.     Ptr cursor_ID_or_Ptr[1000];    /* the true size depends on the size of the resource */
  116.     } *rot_cursor;
  117.  
  118. extern short current_font,current_size,current_style,curr_font_index;
  119.  
  120. /* #define    kNoEvents                0        / * no events mask */
  121. /* GMac is used to hold the result of a SysEnvirons call. This makes
  122.    it convenient for any routine to check the environment. It is
  123.    global information, anyway. */
  124. SysEnvRec    gMac;                /* set up by Initialize */
  125.  
  126. /* GHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
  127.    trap is available. If it is false, we know that we must call GetNextEvent. */
  128. Boolean        gHasWaitNextEvent;    /* set up by Initialize */
  129. Boolean        gHasResolveAlias;
  130. Boolean        gHasCustomPutFile;
  131.  
  132. /* GInBackground is maintained by our OSEvent handling routines. Any part of
  133.    the program can check it to find out if it is currently in the background. */
  134. Boolean        gInBackground=false;        /* maintained by Initialize and DoEvent */
  135.  
  136. /* kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
  137.    SysEnvRec we understand. */
  138. #define    kSysEnvironsVersion        1
  139. #define _WaitNextEvent    0xA860
  140. #define _AliasDispatch    0xA823
  141. #define _Gestalt        0xA1AD
  142. #define _InitGraf        0xA86E
  143. #define _Unimplemented    0xA89F
  144.  
  145. #define TrapType Trap_Type
  146. typedef unsigned char Trap_Type;        /* changed name, to avoid a conflict with
  147.                                         newer standard headers which might have that
  148.                                         declaration */
  149. void my_init(void);
  150. void SetUpMenus(void);
  151. void crea_menu_font(void);
  152. void set_marks_size(void);
  153. void set_marks_style(void);
  154. void DoFile(short);
  155. void SetUpCursors(void);
  156. Boolean _TrapAvailable(short,TrapType);
  157. unsigned long GetSleep(void);
  158.  
  159.  
  160.  
  161. static void my_init()
  162. {
  163. register short i;
  164.     SetUpMenus();
  165.     for(i=0;i<n_max_windows;i++)
  166.         my_windows[i].used=false;
  167.     SetUpCursors();
  168.     for(i=0;i<n_max_foreign;i++)
  169.         foreign_window[i]=NULL;
  170. }
  171.  
  172. void install_handlers(window,upd_handler,act_handler)
  173. WindowPtr window;
  174. upd_proc upd_handler;
  175. upd_proc act_handler;
  176. {
  177. short i=0;
  178. while(i<n_max_foreign){
  179.      if(foreign_window[i]==NULL){
  180.          foreign_window[i]=window;
  181.          update_handler[i]=upd_handler;
  182.          activate_handler[i]=act_handler;
  183.          return;
  184.          }
  185.      i++;
  186.      }
  187. }
  188.  
  189. void remove_handlers(window)
  190. WindowPtr window;
  191. {
  192. short i=0;
  193. while(i<n_max_foreign){
  194.      if(foreign_window[i]==window){
  195.          foreign_window[i]=NULL;
  196.          return;
  197.          }
  198.      i++;
  199.      }
  200. }
  201.  
  202. void UpdateFilter (theEvent)
  203. register EventRecord *theEvent;
  204. /* to be called exclusively for update & activate events */
  205. {
  206. /* It's annoying to be obliged to handle update and activate events; furthermore,
  207. according to TN 304 update events should never be ignored, even during a ModalDialog
  208. (which ignores them if they are not for the dialog itself, unless you specify a 
  209. filter which handles them).
  210.  Hence, when suntar began to have a number of windows and dialogs, I preferred
  211. to do things in a way that is complex but surely works in any situation,
  212. centralizing the handling of updates and activates: when calling ModalDialog one
  213. must use this filter, when calling MainEvent or get_event updates and activates
  214. are NOT returned to the caller, but are handled internally (just as happens to
  215. updates when one installs a picture in windowPic, but probably nobody has ever
  216. used that method for a dialog).
  217.  
  218. It's always a good programming rule to rewrite something when the program grows
  219. and the old, simple method begins to be inadequate for the job.
  220. */
  221. if(ourTE(theEvent->message)){
  222.     if(theEvent->what==updateEvt)
  223.         UpdateWindow((WindowPtr)theEvent->message);
  224.     else    /* activate */
  225.         DoActivate((WindowPtr)theEvent->message,theEvent->modifiers & activeFlag );
  226.     theEvent->what=nullEvent;
  227.     }
  228. else if(theEvent->message){
  229.     short entry_n;
  230.     for(entry_n=0;entry_n<n_max_foreign;entry_n++){
  231.         if((WindowPtr)theEvent->message==foreign_window[entry_n]){
  232.             if(theEvent->what==updateEvt){
  233.                 if(update_handler[entry_n])
  234.                     (*update_handler[entry_n])(theEvent);
  235.                 }
  236.             else{
  237.                 if(activate_handler[entry_n])
  238.                     (*activate_handler[entry_n])(theEvent);
  239.                 }
  240.             theEvent->what=nullEvent;
  241.             break;
  242.             }
  243.         }
  244.     }
  245. return;
  246. }
  247.  
  248. void MainEvent()
  249. /* see the comment at the beginning of suntar.c for understanding this routine 
  250. and the two following ones: suntar has NOT a main event loop... */
  251. {
  252.     EventRecord        myEvent;
  253.     if(get_event(&myEvent)){
  254.         if(my_event_filter!=NULL) (*my_event_filter)(&myEvent);
  255.         handle_event(&myEvent);
  256.         }
  257. }
  258.  
  259.  
  260. Boolean get_event(myEvent)
  261. EventRecord        *myEvent;
  262. {
  263.     Boolean retcode;
  264.     if(curr_window)
  265.         TEIdle(curr_window->TEH);
  266.  
  267.  
  268.     #ifdef SUNTAR
  269.     #define MY_MASK (everyEvent& ~diskMask)
  270.     if( ! (retcode=GetOSEvent (diskMask,myEvent)) ){    /* otherwise the disk is mounted... */
  271.     #else
  272.     #define MY_MASK everyEvent
  273.     #endif
  274.         /* use WNE if it is available */
  275.         if ( gHasWaitNextEvent ) {
  276.             long delay=GetSleep();
  277.             /*AdjustCursor(mouse, cursorRgn);*/
  278.             if(delay==-1){
  279.                 OSEventAvail(kNoEvents, myEvent);    /* we aren't interested in any events */
  280.                                                     /* just the mouse position */
  281.                 MaintainCursor(myEvent->where);
  282.                 }
  283.             retcode= WaitNextEvent(MY_MASK, myEvent,
  284.                 delay, NULL/*cursorRgn*/);
  285.                 /* in suntar disk insertions are masked, but
  286.                 WaitNextEvent returns, so that the event may be caught by the
  287.                 following GetOSEvent call above, hence the disk is mounted only if 
  288.                 it's a Mac disk */
  289.             }
  290.         else {
  291.             SystemTask();
  292.             retcode= GetNextEvent(MY_MASK, myEvent);
  293.             }
  294.         #ifdef SUNTAR
  295.         }
  296.         #endif
  297.     MaintainCursor(myEvent->where);
  298.     if(retcode && (myEvent->what==updateEvt || myEvent->what==activateEvt) ){
  299.         UpdateFilter(myEvent);
  300.         return myEvent->what!=nullEvent;
  301.         }
  302.     return retcode;
  303. }
  304.  
  305. void handle_event(myEvent)
  306.     register EventRecord    *myEvent;
  307. {
  308.     WindowPtr        whichWindow;
  309. /*    RgnHandle        cursorRgn;*/
  310.     short            code;
  311.  
  312. /*printf("event=%x\n",myEvent->what);*/
  313. /*print_number("event=",(short)myEvent->what);*/
  314.  
  315.     switch (myEvent->what) {
  316.     case mouseDown:
  317.         code=FindWindow( myEvent->where, &whichWindow );
  318. /*printf("place=%d\n",code);*/
  319.         switch (code) {
  320.         case inDesk:
  321.             SysBeep(5);
  322.             break;
  323.         case inMenuBar:
  324.             MaintainMenus();
  325.             DoCommand( MenuSelect(myEvent->where));
  326.             break;
  327.         case inSysWindow:
  328.             SystemClick( myEvent, whichWindow );
  329.             break;
  330.         case inDrag:
  331.             {
  332.             Rect    dragRect;
  333.             dragRect.left=0;
  334.             dragRect.top=MBARHEIGHT;
  335.             dragRect.right=screenBits.bounds.right;
  336.             dragRect.bottom=screenBits.bounds.bottom;
  337.             InsetRect(&dragRect,4,4);
  338.             DragWindow( whichWindow, myEvent->where, &dragRect );
  339.             }
  340.             break;
  341.         case inGrow:
  342.             if (curr_window)
  343.                 MyGrowWindow( whichWindow, myEvent->where );
  344.             break;
  345.         case inZoomOut:
  346.         case inZoomIn:
  347.             if(curr_window)
  348.                 myZoomWindow(whichWindow,myEvent->where,code);
  349.             break;
  350.         case inGoAway:
  351.             if (curr_window)
  352.                 if (TrackGoAway( whichWindow, myEvent->where) )
  353.                     DoFile(opClose);
  354.             break;
  355.         case inContent:
  356.             if (whichWindow != FrontWindow()){
  357.                 SelectWindow(whichWindow);
  358.                 }
  359.             else
  360.                 if (curr_window)
  361.                     DoContent(whichWindow, myEvent);
  362.             break;
  363.         default: ;
  364.         } /* end switch FindWindow */
  365.         break;
  366.     case autoKey:
  367.         if((myEvent->modifiers & cmdKey) != 0)    /*niente autorepeat sui comandi!
  368.                     --no autorepeat on commands ! */
  369.             break;    /* else prosegui in sequenza...
  370.                     -- else behave as a keyDown */
  371.     case keyDown:
  372.         DoKeyDown( (unsigned char) myEvent->message, myEvent->modifiers );
  373.         break;
  374.     /* moved to UpdateFilter
  375.     case activateEvt:
  376.         if (ourTE((WindowPtr)myEvent->message)){
  377.             SetPort((WindowPtr)myEvent->message);
  378.             DoActivate((WindowPtr)myEvent->message,myEvent->modifiers & activeFlag );
  379.             }
  380.         else{
  381.             if (myEvent->modifiers & activeFlag )
  382.                 SetPort((WindowPtr)myEvent->message);
  383.             }
  384.         break;
  385.         */
  386.     case kOSEvent:    /* eventi del MultiFinder */
  387.         {
  388.         WindowPtr w;
  389.         switch ((myEvent->message >> 24) & 0x0FF) {        /* high byte of message */
  390.             case kMouseMovedMessage:
  391.                 /*MaintainCursor(myevent->where);*/            /* mouse-moved is an idle event */
  392.                 break;
  393.             case kSuspendResumeMessage:
  394.                 gInBackground = (myEvent->message & kResumeMask) == 0;
  395.                 w=FrontWindow();
  396.  
  397.                 myEvent->message=(long)w;
  398.                 myEvent->what=activateEvt;        /* suspend/resume is also an activate/deactivate */
  399.                 myEvent->modifiers = !gInBackground ? activeFlag : 0;
  400.                 UpdateFilter(myEvent);        /* my handler of activate events */
  401. #ifdef SUNTAR
  402.                 if(gInBackground){
  403.                     if( going_to_background() && ourTE(w))
  404.                         HiliteWindow (w,false);        /* going_to_background does some
  405.                                 dirty things which may leave the window incorrectly 
  406.                                 highlighted */
  407.                     SetCursor(&arrow);    /* some applications do not set the cursor
  408.                             when they go to foreground... */
  409.                     MainEvent();    /* per andarci subito in background... non 
  410.                         posso fare aspettare la prossima chiamata 
  411.                         --immediately go to background: in suntar going_to_background
  412.                         may do a delay, I can't return to a routine which is going to do
  413.                         further work before calling MainEvent again
  414.                         when MultiFinder is waiting to switch me to background
  415.                         */
  416.                     return;
  417.                     }
  418. #endif
  419.                 break;
  420.         }}
  421.         break;
  422.     /* moved to UpdateFilter
  423.     case updateEvt: 
  424.         if (ourTE((WindowPtr)myEvent->message)) 
  425.             UpdateWindow((WindowPtr)myEvent->message);
  426.         break;
  427.     */
  428.     case diskEvt:
  429.     /*    It is not a bad idea to at least call DIBadMount in response
  430.         to a diskEvt, so that the user can format a floppy. */
  431.         #ifndef SUNTAR
  432.         if ( hiword(myEvent->message) != noErr )
  433.             DIBadMount(badmount_point, myEvent->message);
  434.         #else
  435.         unexpected_disk_insertion(myEvent->message);
  436.         #endif
  437.  
  438.         break;
  439.     default: ;
  440.     } /* end of case myEvent->what */
  441. }
  442.  
  443. /* gestione tasti */
  444.  
  445. void DoKeyDown( theChar, modifiers )
  446. register unsigned char theChar;
  447. short modifiers;
  448. {
  449.  
  450. if ((modifiers & cmdKey) != 0) {
  451.     long mnk;
  452.     MaintainMenus();
  453.     mnk=MenuKey( theChar );
  454.     if(hiword(mnk) == 0){ /* non esiste un tale comando, o non è abilitato...
  455.                     --command not existing or not enabled
  456.                     */
  457.         SysBeep(5);
  458.         FlushEvents( keyDownMask|autoKeyMask, 0 );
  459.         }
  460.     else{
  461.         SetPort(curr_window);
  462.         DoCommand( mnk );
  463.         }
  464.     return;
  465.     }
  466. else if (curr_window){
  467.     SetPort(curr_window);
  468.     if (theChar== enter_key) /* il TextEdit non lo gestisce
  469.                 --TextEdit does not know that enter is a "return" char
  470.                  */
  471.         theChar=CR;
  472.     if( theChar >= 28 &&theChar <= 31){    /* è un tasto cursore 
  473.                             --a cursor key
  474.                             */
  475.         TEKey( theChar, TEH );
  476.         }
  477.     else if    ( theChar == DelChar) /* questo è gestito correttamente, ma per poter 
  478.                                 poi aggiungere al programma l'undo bisogna gestirlo 
  479.                                 direttamente, e la gestione per console è diversa... */
  480.         if( curr_window->flags&READONLY && ((**TEH).selStart<curr_window->lastPrompt 
  481.             || (**TEH).selStart==curr_window->lastPrompt &&(**TEH).selStart==(**TEH).selEnd))
  482.             SysBeep(5);
  483.         else{
  484.             TEKey( theChar, TEH );
  485.             curr_window->dirty = 1;
  486.             }
  487. #ifndef AUTOSELECT
  488.     else if( curr_window->flags&READONLY && (**TEH).selStart<curr_window->lastPrompt){
  489.         SysBeep(5);
  490.         FlushEvents( keyDownMask|autoKeyMask, 0 );    /* è facile battere più caratteri 
  491.                                     insieme, e il beep dà tempo per accumularli...*/
  492.         }
  493. #endif
  494.     else if ( curr_window->flags&READONLY && curr_window->lastPrompt == 32767){
  495.     /* a console window completely read-only */
  496.         SysBeep(5);
  497.         FlushEvents( keyDownMask|autoKeyMask, 0 );
  498.         }
  499.     else if((*TEH)->teLength - ((*TEH)->selEnd - (*TEH)->selStart) + 1 < maxTElength ){
  500.         /* a console window with a read-only part on top and a read/write part
  501.         on bottom */
  502.         if(theChar==CR&&(curr_window->flags&CONSOLE)){
  503.             TESetSelect (32767L ,32767L, TEH);
  504.             TEKey( CR, TEH );
  505.             curr_window->lastPrompt=32767;    /* questo è l'unico segno visibile dall'esterno 
  506.                                             che il return c'è stato
  507.                                             -- it's the only state change remembering
  508.                                             that there was a carriage return */
  509.             }
  510.         else{
  511.         /* non so se sia il caso di gestire a parte anche altri caratteri, tipo l'escape */
  512. #ifdef AUTOSELECT
  513.             if( curr_window->flags&READONLY && (**TEH).selStart<curr_window->lastPrompt)
  514.                 TESetSelect(32767L,32767L,TEH);
  515. #endif
  516.             TEKey( theChar, TEH );
  517.             curr_window->dirty = 1;
  518.             }
  519.         }
  520.     else{    /* buffer pieno ! */
  521.         SysBeep(5);
  522.         ParamText("\pNo more space in window",PNS,PNS,PNS);
  523.         my_alert();
  524.         FlushEvents( keyDownMask|autoKeyMask, 0 );
  525.         }
  526.     SCR_BAR_AND_TEXT_IN_SYNC
  527.     }
  528. }
  529.  
  530.  
  531. void DoActivate(w,active_flag)
  532. register window_def* w;
  533. short active_flag;
  534. {
  535. GrafPtr    savePort;
  536. if (!active_flag ) GetPort( &savePort );
  537. SetPort(w);        /* pare che non guasti, per proteggersi da DA e (sotto
  538.                 MultiFinder) altri programmi che si comportino male; e poi,
  539.                 tutto il modulo presume che se curr_window è != NULL allora
  540.                 la porta corrente è lei
  541.                 -- in this module, all routines think that if curr_window is
  542.                 not 0, then the current port is curr_window */
  543. if (active_flag ) {
  544.     Rect r;
  545.     curr_window=w;
  546.     TEH=w->TEH;
  547.     TEActivate( w->TEH );
  548.     if(curr_window==&my_windows[0]){
  549.         /* posso averci fatto delle print, col che posizione e dimensioni
  550.         complessive sono cambiate
  551.         -- if printf has added text while the window was not in foreground,
  552.         the scrollbar was not updated to reflect the current state
  553.         */
  554.         SCR_BAR_AND_TEXT_IN_SYNC
  555.         }
  556.     ShowControl( w->vScroll );
  557. #ifdef HSCROLL
  558.     if( w->flags&HSCROLL) ShowControl( w->hScroll);
  559. #endif
  560.     TEFromScrap();
  561.     /* the growbox needs to be redrawn on activation: */
  562.     r=((WindowPtr)w)->portRect;
  563.     r.top = r.bottom - (SBarWidth+1);
  564.     r.left = r.right - (SBarWidth+1);
  565.     InvalRect(&r);        
  566.     }
  567. else {
  568.     ZeroScrap();
  569.     TEToScrap();
  570.     TEDeactivate(w->TEH);
  571.     HideControl( w->vScroll );
  572. #ifdef HSCROLL
  573.     if( w->flags&HSCROLL) HideControl( w->hScroll );
  574. #endif
  575.     DrawGrowIcon(w);
  576.     curr_window=NULL;
  577.     SetPort( savePort );
  578.     }
  579. }
  580.  
  581.  
  582. static void SetUpMenus()
  583. {
  584.     short    i;
  585.  
  586.     myMenus[appleM] = GetMenu( appleID );
  587.     if(myMenus[appleM]==NULL){
  588.         SysBeep(5);
  589.         SysBeep(5);
  590.         SysBeep(5);
  591.         ExitToShell();
  592.         }
  593.     n_about_entries=CountMItems(myMenus[appleM]);
  594.     if(n_about_entries>0)
  595.         AppendMenu(myMenus[appleM], "\p(-");
  596.     AddResMenu( myMenus[appleM], 'DRVR' );
  597.  
  598.     myMenus[fileM] = GetMenu(fileID);
  599.     quit_selection=CountMItems(myMenus[fileM]);
  600.  
  601.     crea_menu_font();
  602. #ifdef SUNTAR
  603.     hqxM=GetMenu(hqxID);
  604.     InsertMenu(hqxM, -1);
  605. #endif
  606.  
  607.     myMenus[editM] = GetMenu(editID);
  608.     myMenus[prefM] = GetMenu(prefID);
  609.     for ( (i=appleM); (i<sizeof(myMenus)/sizeof(MenuHandle)); i++ ) 
  610.         InsertMenu(myMenus[i], 0) ;
  611.     if(my_add_menus!=NULL)
  612.         (*my_add_menus)();
  613.  
  614.     DrawMenuBar();
  615.  
  616. }
  617.  
  618.  
  619. static void crea_menu_font()
  620. {
  621. short i,font_n;
  622.     Str255 fontName;
  623. /* gestione menù dei font */
  624. /* ispirata al dimostrativo in Pascal di Carlo Rogialli, SP Computer aprile 1989
  625. -- inspired to the demo program in Pascal by Carlo Rogialli, in an italian magazine 
  626.  */
  627.     fontM[0]=GetMenu(fontID);
  628.     AddResMenu( fontM[0], 'FONT' );
  629.     fontM[1]=GetMenu(sizeID);
  630.     fontM[2]=GetMenu(styleID);
  631.     for(i=0;i<3;i++)
  632.         InsertMenu(fontM[i], -1);
  633.  
  634.     curr_font_index=1+CountMItems(fontM[0]);
  635.     do{
  636.         curr_font_index--;
  637.         GetItem(fontM[0],curr_font_index,&fontName);
  638.         GetFNum(fontName,&font_n);
  639.         /*printf("font %P %d\n",fontName,font_n);*/
  640.         }
  641.     while(font_n!=current_font &&curr_font_index>0);    /* se il font monaco non è presente 
  642.                                                 si comporta stranamente ma almeno non crasha */        
  643.     SetItemMark (fontM[0], curr_font_index, '•');
  644.  
  645.     for(i=CountMItems(fontM[1]);i>0;i--){    /* if a size is checked, accept it; otherwise,
  646.                         use the default value (9) */
  647.         short markChar;
  648.         GetItemMark (fontM[1],i,&markChar);
  649.         if(markChar==checkMark){
  650.             char sizestr[16];
  651.             GetItem(fontM[1],i,sizestr);
  652.             current_size=pstrtoi(sizestr);
  653.             break;
  654.             }
  655.         }
  656.     set_marks_size();
  657.     set_marks_style();
  658. }
  659.  
  660. static void set_marks_size()
  661. {
  662. short i,size;
  663. char sizestr[16];
  664. for(i=CountMItems(fontM[1]);i>0;i--){
  665.     GetItem(fontM[1],i,sizestr);
  666.     if(RealFont(current_font, (size=pstrtoi(sizestr))) )
  667.         SetItemStyle(fontM[1],i,outline);
  668.     else
  669.         SetItemStyle(fontM[1],i,0);
  670.     CheckItem (fontM[1], i, size==current_size );
  671.     }
  672. }
  673.  
  674. static void set_marks_style()
  675. {
  676. short i,mask;
  677. CheckItem (fontM[2], 1, current_style==0 );
  678. mask=1;
  679. for(i=2;i<=6;i++){
  680.     CheckItem (fontM[2], i, (current_style&mask) !=0 );
  681.     mask <<=1;
  682.     }
  683. }
  684.  
  685. void DoFont( mResult)
  686. long mResult;
  687. {
  688.     Str255    fontName;
  689.  
  690.     switch (hiword(mResult)) {
  691.     case fontID:
  692.         CheckItem (fontM[0], curr_font_index, false );
  693.         SetItemMark (fontM[0], curr_font_index=loword( mResult ), '•');
  694.         GetItem(fontM[0],curr_font_index,&fontName);
  695.         GetFNum(fontName,¤t_font);
  696.         set_marks_size();    /* è cambiato l'essere real font o no
  697.                             -- "real font" sizes are represented differently,
  698.                             hence I must recompute their state */
  699.         break;
  700.     case sizeID:
  701.         {char sizestr[16];
  702.         GetItem(fontM[1],loword( mResult ),sizestr);
  703.         current_size= pstrtoi(sizestr);
  704.         }
  705.         set_marks_size();
  706.         break;
  707.     case styleID:
  708.         if(loword( mResult )==1)
  709.             current_style=0;
  710.         else
  711.             current_style ^= (1<< (loword( mResult )-2)) ;
  712.         set_marks_style();
  713.         break;
  714.     }
  715. }
  716.  
  717. void DoCommand( mResult )
  718. long mResult;
  719. {
  720.     short        theItem, temp;
  721.  
  722.     theItem = loword( mResult );
  723.     switch (hiword(mResult)) {
  724.     case appleID:
  725.         if(theItem<=n_about_entries)
  726.             my_handle_menus(mResult);
  727.         else
  728.             {Str255    name;
  729.             GrafPtr savePort;
  730.  
  731.             GetPort(&savePort);
  732.             GetItem(myMenus[appleM], theItem, &name);
  733.             OpenDeskAcc( &name );
  734.             SetPort( savePort );
  735.             }
  736.         break;
  737.     case fileID: 
  738.         if(theItem==quit_selection){
  739.             if(my_at_exit!=NULL)
  740.                 if( !(*my_at_exit)()) break;    /* quit cancelled */
  741.             DoFile(opQuit);
  742.             HiliteMenu(0);
  743.             ExitToShell();
  744.             }
  745.         else
  746.             (*my_handle_menus)(mResult);
  747.         break;
  748.     case editID:
  749. /* la funzione MaintainMenus dovrebbe disabilitare i comandi di editing se non esiste 
  750. una finestra corrente, ma per prudenza è meglio controllare sempre...
  751. -- The commands are disabled when they are meaningless, but it's better to check
  752. anyway
  753. */
  754.         if (SystemEdit(theItem-1)==0) {
  755. #ifndef AUTOSELECT
  756.             if( curr_window==NULL || theItem!=copyCommand && (curr_window->flags&READONLY) &&
  757.                 (**TEH).selStart<curr_window->lastPrompt ){
  758.                 SysBeep(5);
  759.                 break;
  760.                 }
  761. #else
  762.             if( curr_window==NULL ||  theItem!=copyCommand && theItem!=pasteCommand && 
  763.                 (curr_window->flags&READONLY) && (**TEH).selStart<curr_window->lastPrompt ) {
  764.                 SysBeep(5);
  765.                 break;
  766.                 }
  767.             if( theItem==pasteCommand && (curr_window->flags&READONLY) ){
  768.             /* un paste in una console si comporta in modo complicato: a parte che 
  769.             comunque non fa il paste di caratteri CR, accetta di essere eseguito 
  770.             anche quando non si è dopo il prompt, portandocisi automaticamente, e se 
  771.             è selezionato qualcosa fa un copy di esso, prché sia nella parte read only
  772.             -- a paste to a console is handled in a complex way: it performs autocopy
  773.             (if something was selected, copy it to the clipboard), then autoselect
  774.             (if the selection point is in the read-only portion of the window, move
  775.             it to the end), and it truncates long clipboards and refuses to paste
  776.             carriage returns */
  777.                 if( curr_window->lastPrompt == 32767 ){
  778.                     /* è del tutto readonly, non console, quindi ho sbagliato a non dare errore */
  779.                     SysBeep(5);
  780.                     break;
  781.                     }
  782.                 if( (**TEH).selStart < curr_window->lastPrompt ){
  783.                     /* autocopy */
  784.                     if( (**TEH).selStart != (**TEH).selEnd && 
  785.                         (**TEH).selEnd < curr_window->lastPrompt)
  786.                             TECopy (TEH);
  787.                     TESetSelect(32767L,32767L,TEH);
  788.                     }
  789.                 }
  790. #endif
  791.             switch (theItem) {
  792.             case cutCommand:
  793.                 TECut( TEH );
  794.                 curr_window->dirty = 1;
  795.                 break;
  796.             case copyCommand:
  797.                 TECopy( TEH );
  798.                 break;
  799.             case pasteCommand:
  800.                 {
  801.                 register short i=TEGetScrapLen();
  802.                 if(curr_window->flags&CONSOLE && i>300 ) i=300; /* troppo per una riga sola... */
  803.                 if ( i + ((*TEH)->teLength -
  804.                             ((*TEH)->selEnd - (*TEH)->selStart)) > maxTElength ){
  805.                     ParamText("\pInsufficient space for pasting",PNS,PNS,PNS);
  806.                     my_alert();
  807.                     }
  808.                 else{
  809.                     if( curr_window->flags&CONSOLE){
  810.                 /* in modalità console, non ha senso il paste di un carriage return! */
  811.                         char **scrap= TEScrapHandle();
  812.                         register char *p,*q;
  813.                         TEDelete(TEH);
  814.                         HLock(scrap);    /*TEInsert vuole un Ptr...*/
  815.                         q= *scrap;
  816.                         while(i>0){
  817.                             p=q;
  818.                             while(i>0&&*q!=CR) q++,--i;
  819.                             if(p!=q)TEInsert(p,(long)(q-p),TEH);
  820.                             if(i>0){    /* e quindi *q==CR */
  821.                                 TEKey(' ',TEH);
  822.                                 q++;i--;
  823.                                 }
  824.                             }
  825.                         HUnlock(scrap);
  826.  
  827.                         /*for(n=0;n<i;n++)
  828.                             TEKey ( ((*scrap)[n]==CR) ? ' ' : (*scrap)[n] ,TEH); */
  829.                         }
  830.                     else
  831.                         TEPaste( TEH );
  832.                     curr_window->dirty = 1;
  833.                     }
  834.                 }
  835.                 break;
  836.             case clearCommand:
  837.                 TEDelete( TEH );
  838.                 curr_window->dirty = 1;
  839.                 break;
  840.             default: ;/* non esistono altri comandi abilitati*/
  841.             }
  842.             SCR_BAR_AND_TEXT_IN_SYNC
  843.         }
  844.         break;
  845.     case prefID:
  846.         switch(theItem){
  847.         case pmAutowrap:
  848.             {short markChar;
  849.             GetItemMark (myMenus[prefM], pmAutowrap, &markChar);
  850.             CheckItem (myMenus[prefM], pmAutowrap, !markChar);
  851.             if(my_windows[0].used) apply_preferences(&my_windows[0]);
  852.             }
  853.             break;
  854.         default:
  855.             (*my_handle_menus)(mResult);
  856.         }
  857.         break;
  858.     case fontID:
  859.     case sizeID:
  860.     case styleID:
  861.         DoFont( mResult);
  862.         if(my_windows[0].used) apply_preferences(&my_windows[0]);
  863.         break;
  864.     default:
  865.         (*my_handle_menus)(mResult);
  866.     }
  867.     HiliteMenu(0);
  868. }
  869.  
  870. static void DoFile( operation )
  871. short        operation;
  872.  
  873. {
  874.     switch (operation) {
  875.     case opClose:
  876.         if(curr_window!=NULL)
  877.             CloseMyWindow();
  878.         break;
  879.     case opQuit:
  880.         ZeroScrap();
  881.         TEToScrap();
  882.         break;
  883.     }
  884. }
  885.  
  886.  
  887. void MaintainCursor(pt)
  888. Point        pt;
  889. {
  890. /* lo chiamo dopo GetNextEvent, col che lo so già dove sta il mouse (al più, l'evento
  891. potrebbe essere un po' vecchio, se il programma ha delle situazioni in cui per lungo
  892. tempo non riceve eventi, la posizione così determinata può essere diversa da quella corrente) */
  893. static unsigned long next_rotation=0;
  894. static short current_cursor=0;
  895.  
  896.     if(gInBackground) return;
  897.     if(sto_lavorando){
  898.         if(((WindowPeek)FrontWindow())->windowKind<0)
  899.             /*SetCursor(&arrow) no, the desk accessory will take its decision,
  900.                 anyway the event which brought it to front caused a SetCursor(&arrow) */
  901.                 ;
  902.         else{
  903.             if(Ticks>next_rotation){
  904.                 next_rotation=Ticks+rot_cursor->delay;
  905.                 if(++current_cursor>=rot_cursor->n_cursors) 
  906.                     current_cursor=0;
  907.                 }
  908.             SetCursor( rot_cursor->cursor_ID_or_Ptr[current_cursor] );
  909.             }
  910.         }
  911.     else{
  912.         current_cursor=0;
  913.         if (curr_window && (WindowPtr)FrontWindow()==(WindowPtr)curr_window) {
  914.             SetPort(curr_window);
  915.             GlobalToLocal(&pt);
  916.             if ( PtInRect(pt, &(**TEH).viewRect ) ){
  917.                 SetCursor( &editCursor);
  918.                 return;
  919.                 }
  920.             }
  921.         SetCursor( &arrow );
  922.         }
  923. }
  924.  
  925. void MaintainMenus()
  926. {
  927.  
  928. /*
  929. In presenza di console, readonly etc. le condizioni per cui i comandi del menù
  930. Edit sono leciti diventano complicate, ho cercato di copiarle da DoCommand, con
  931. l'idea che è meglio lasciarne abilitati di quelli che poi danno errore piuttosto
  932. che disabilitarne di quelli che sono eseguibili
  933. -- the conditions for allowing a command are complex, but since doCommands does
  934. its own checks, I duplicated those tests and in case of difference it's
  935. better to let the item enabled when it should be disabled then vice-versa
  936. */
  937.  
  938. WindowPtr w=FrontWindow();
  939. Boolean selected,all_readonly,sel_readonly;
  940.  
  941.     if ( ! ourTE(w) ) {
  942.         Boolean en=isDAwindow(w);
  943.         en_dis_edit(undoCommand ,en);
  944.         en_dis_edit(pasteCommand ,en);
  945.         en_dis_edit(cutCommand ,en);
  946.         en_dis_edit(copyCommand ,en);
  947.         en_dis_edit(clearCommand ,en);
  948.         }
  949.     else {
  950.         /*
  951.         EnableItem(myMenus[prefM],pmAutowrap);
  952.         EnableItem(myMenus[prefM],pmFont);
  953.         EnableItem(myMenus[prefM],pmSize);
  954.         EnableItem(myMenus[prefM],pmStyle);
  955.         */
  956.         DisableItem( myMenus[editM], undoCommand );
  957.         selected = (**TEH).selStart!=(**TEH).selEnd;
  958.         en_dis_edit(copyCommand,selected);
  959.         if(curr_window->flags&CONSOLE){
  960. /* questo è pensato per una console con autoselect e autocopy */
  961.             all_readonly= curr_window->lastPrompt==32767;
  962.             sel_readonly= (**TEH).selStart<curr_window->lastPrompt;
  963.             en_dis_edit(cutCommand, selected&&!sel_readonly);
  964.             en_dis_edit(clearCommand, selected&&!sel_readonly);
  965.             en_dis_edit(pasteCommand,!all_readonly&&(TEGetScrapLen()>0||selected));
  966.             }
  967.         else{
  968.             en_dis_edit(cutCommand, selected);
  969.             en_dis_edit(clearCommand, selected);
  970.             en_dis_edit(pasteCommand,TEGetScrapLen()>0);
  971.             }
  972.  
  973.     }
  974.     #ifdef SUNTAR
  975.     MaintainApplSpecificMenus();
  976.     #endif
  977. }
  978.  
  979. void en_dis_edit(item,flag)
  980. short item;
  981. Boolean flag;
  982. {
  983. if(flag)
  984.     EnableItem(myMenus[editM], item);
  985. else
  986.     DisableItem(myMenus[editM], item);
  987. }
  988.  
  989. static void SetUpCursors()
  990. {
  991.     CursHandle    hCurs;
  992.     short i;
  993.  
  994.     hCurs = GetCursor(1);
  995.     editCursor = **hCurs;
  996.     hCurs = GetCursor(watchCursor);
  997.     waitCursor = **hCurs;
  998.  
  999.     ResrvMem ((Size)200);
  1000.     hCurs=GetResource('acur',128);
  1001.     HLock(hCurs);
  1002.     rot_cursor= *hCurs;
  1003.     if(rot_cursor->delay==0) rot_cursor->delay=10;
  1004.  
  1005.     for(i=0;i<rot_cursor->n_cursors;i++){
  1006.         ResrvMem ((Size)sizeof(Cursor));
  1007.         hCurs=GetCursor(hiword(rot_cursor->cursor_ID_or_Ptr[i]));
  1008.         HLock(hCurs);
  1009.         rot_cursor->cursor_ID_or_Ptr[i]= *hCurs;
  1010.         }
  1011. }
  1012.  
  1013.  
  1014. short SilentSuppression (nlines)
  1015. short nlines;
  1016. /* questa funzione serve per implementare finestre di console: in quel caso, 
  1017. l'utente può tornare indietro a vedere che è successo nel passato ma la storia
  1018. passata non gli interesserà poi moltissimo, per cui se il buffer del TextEdit 
  1019. si riempie è molto meno dannoso per lui cancellargli a tradimento le cose più 
  1020. vecchie che dare errore.
  1021. La funzione cerca di cancellare le prime nlines righe, ma riduce il numero se 
  1022. le ultime sono visibili sullo schermo o fanno parte della selezione, in ogni
  1023. caso ritorna il numero di righe soppresse. Sullo schermo l'unico effetto 
  1024. visibile è uno spostamento del bottone della scrollbar verticale (la posizione 
  1025. relativa entro il buffer è cambiata).
  1026. -- Deletes the first nlines lines of the content of the window, without
  1027. letting the user suspect what's happening (the scroll bar button is the only
  1028. thing on the screen which may be modified)
  1029. */
  1030. {
  1031. short olds,olde,deltax,deltay,oktodelete,charsToDelete,linesOutOfScreen;
  1032. Rect oldr;
  1033. GrafPtr savePort;
  1034. register TERec *TEp;
  1035.  
  1036.     TEp = *my_windows[0].TEH;
  1037.     linesOutOfScreen=(TEp->viewRect.top-TEp->destRect.top)/TEp->lineHeight;
  1038.     if(linesOutOfScreen<nlines) nlines=linesOutOfScreen;
  1039.  
  1040.     do{
  1041.         if(nlines<=0) return 0;
  1042.         charsToDelete= TEp->lineStarts[nlines];
  1043.         if( ! (oktodelete=TEp->selStart>charsToDelete) ) 
  1044.             nlines--;
  1045.         }
  1046.     while(!oktodelete);
  1047.  
  1048.     olds=TEp->selStart-charsToDelete;
  1049.     olde=TEp->selEnd-charsToDelete;
  1050.     oldr=TEp->destRect;
  1051.  
  1052.     GetPort( &savePort );
  1053.     SetPort( &my_windows[0]);
  1054.     HidePen();
  1055.     TESetSelect(0L, (long) charsToDelete, my_windows[0].TEH);
  1056.     TEDelete (my_windows[0].TEH);
  1057.     TESetSelect((long)olds, (long) olde, my_windows[0].TEH);
  1058.     TEp = *my_windows[0].TEH;
  1059.     deltax= oldr.left - TEp->destRect.left;
  1060.     deltay= oldr.top+nlines*TEp->lineHeight - TEp->destRect.top;
  1061.     if(deltax || deltay)
  1062.         TEScroll(deltax,deltay,my_windows[0].TEH);
  1063.     /* si potrebbe fare un ValidRect, ma allora bisogna sottrarci la vecchia regione
  1064.     di update e io questi giochi non li so ancora fare. Comunque, ho provato e il
  1065.     main loop non riceve alcun evento di update dopo il fatto, se qualcuno ritraccia
  1066.     allora è direttamente il TextEdit */
  1067.     ShowPen();
  1068.     MaintainScrollBars(&my_windows[0]);
  1069.  
  1070.     if(my_windows[0].lastPrompt!=32767)
  1071.         if((my_windows[0].lastPrompt -= charsToDelete) <0)
  1072.             my_windows[0].lastPrompt=0;
  1073.     SetPort(savePort);
  1074.     return nlines;
  1075. }
  1076.  
  1077. #if 0
  1078. /*  from TESample.c */
  1079. /*    Check to see if a given trap is implemented. This is only used by the
  1080.     Initialize routine in this program, so we put it in the Initialize segment.
  1081.     The recommended approach to see if a trap is implemented is to see if
  1082.     the address of the trap routine is the same as the address of the
  1083.     Unimplemented trap. */
  1084. /*    1.02 - Needs to be called after call to SysEnvirons so that it can check
  1085.     if a ToolTrap is out of range of a pre-MacII ROM. */
  1086.  
  1087. Boolean TrapAvailable(tNumber,tType)
  1088.     short        tNumber;
  1089.     Trap_Type    tType;
  1090. {
  1091.     if ( ( tType == (unsigned char) ToolTrap ) &&
  1092.         ( gMac.machineType > envMachUnknown ) &&
  1093.         ( gMac.machineType < envMacII ) ) {        /* it's a 512KE, Plus, or SE */
  1094.         tNumber = tNumber & 0x03FF;
  1095.         if ( tNumber > 0x01FF )                    /* which means the tool traps */
  1096.             tNumber = _Unimplemented;            /* only go to 0x01FF */
  1097.     }
  1098.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  1099. } /*TrapAvailable*/
  1100. #else
  1101. /* this one is suggested by Inside Mac volume VI, hence probably it's better;
  1102. but we did not want to have three function to do what a single one would do,
  1103. and a #define for _GetTrapType is evaluated at compile time... */
  1104.  
  1105. #define _GetTrapType(theTrap) ((theTrap & 0x0800) !=0 )
  1106. #define TrapAvailable(theTrap) _TrapAvailable(theTrap,_GetTrapType(theTrap) )
  1107.  
  1108.  
  1109. Boolean    _TrapAvailable(short theTrap,TrapType tType)
  1110. {
  1111.     /* TrapType tType;
  1112.  
  1113.     tType = GetTrapType(theTrap); */
  1114.     if (tType == ToolTrap) {
  1115.         theTrap &= 0x07FF;
  1116.         if (theTrap >= 
  1117.             (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E,ToolTrap) ?
  1118.                 0x0200 : 0x0400) )
  1119.             theTrap = _Unimplemented;
  1120.     }
  1121.  
  1122.     return NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap);
  1123. }
  1124.  
  1125. #endif
  1126.  
  1127.  
  1128. /*    Calculate a sleep value for WaitNextEvent. This takes into account the things
  1129.     that DoIdle does with idle time. */
  1130. #define MAXLONG 0xFFFFFFFF
  1131. unsigned long GetSleep()
  1132. {
  1133.     long        sleep;
  1134.     WindowPtr    window;
  1135.     TEHandle    te;
  1136.  
  1137.     if(sto_lavorando) return 0L;
  1138.     if ( gInBackground)
  1139.         sleep = MAXLONG;
  1140.     else if(!curr_window){
  1141.         #ifndef SUNTAR
  1142.         sleep = MAXLONG;
  1143.         #else
  1144.         sleep = 40;    /* under System 6, with the Finder and WaitNextEvent in ROM, I
  1145.                     do NOT get a null event when an event arrives but it's masked.
  1146.                     Since to be able to catch disk insertions by GetOSEvent and be
  1147.                     MultiFinder aware it's essential to perform a GetOSEvent with
  1148.                     little delay relative to the disk insertion, I must use a short
  1149.                     sleep time even if nothing need be done (it would be better to
  1150.                     call GetNextEvent, since the Finder can't exploit the free time,
  1151.                     and under MultiFinder and System 7 the null event arrives,
  1152.                     but ther is no way to know whether I'm under MultiFinder or not !)
  1153.                     And I was told that the problem may happen under System 7 too,
  1154.                     hence it's better to avoid risking, unless Apple officiallly
  1155.                     declares that not returning that event is a bug and lists all the
  1156.                     System versions containing that bug
  1157.                     */
  1158.         #endif
  1159.         }
  1160.     else{
  1161.         if (curr_window && (*TEH)->selStart == (*TEH)->selEnd )
  1162.             sleep = GetCaretTime();        /* blink time for the insertion point */
  1163.         else
  1164.             sleep=60;    /* non uso le region per aggiornare la forma del cursore, 
  1165.                 quindi ho bisogno di lavorare ogni tanto anche se non ho un punto 
  1166.                 di inserzione lampeggiante
  1167.                 -- I need to be periodically called to update the cursor shape,
  1168.                 it would be better to use the MouseMoved event but this way is easier
  1169.                 */
  1170.         }
  1171.     return sleep;
  1172. } /*GetSleep*/
  1173.  
  1174.  
  1175. void InitConsole()
  1176. {    
  1177.     InitGraf(&thePort);
  1178.     InitFonts();
  1179.     FlushEvents( everyEvent, 0 );
  1180.     InitWindows();
  1181.     InitMenus();
  1182.     MoreMasters();
  1183.     MoreMasters();    /* the typical heap of suntar has 100 used handles, obviously
  1184.                     peek values may go beyond 128, hence three master blocks (one
  1185.                     preallocated and two MoreMasters) avoid having a new nonrelocatable
  1186.                     block placed among relocatable blocks */
  1187.     TEInit();
  1188.     InitDialogs(0L);
  1189.     InitCursor();
  1190.     if(ApplLimit> CurStackBase-(long)REQUIREDSTACK )
  1191.         SetApplLimit(CurStackBase-(long)REQUIREDSTACK);
  1192.     MaxApplZone();
  1193.  
  1194.     /*    Ignore the error returned from SysEnvirons; even if an error occurred,
  1195.         the SysEnvirons glue will fill in the SysEnvRec. You can save a redundant
  1196.         call to SysEnvirons by calling it after initializing AppleTalk. */
  1197.  
  1198.     SysEnvirons(kSysEnvironsVersion, &gMac);
  1199.  
  1200.     /* Make sure that the machine has at least 128K ROMs. If it doesn't, exit. */
  1201.  
  1202.     if (gMac.machineType < 0){SysBeep(5); ExitToShell();}
  1203.  
  1204.     gHasWaitNextEvent = TrapAvailable(_WaitNextEvent /*, ToolTrap*/);
  1205.     gHasResolveAlias  = TrapAvailable(_AliasDispatch /*, ToolTrap*/);
  1206.     gHasCustomPutFile=false;
  1207.     if(TrapAvailable(_Gestalt /*, ToolTrap*/)){
  1208.         long response;
  1209.         OSErr err;
  1210.         #ifdef HAS_GESTALT_GLUE
  1211.         err=Gestalt('stdf',&response);
  1212.         #else    /* the libraries of Think C 4 don't contain Gestalt... */
  1213.         asm{
  1214.             move.l #'stdf',D0
  1215.             dc.w _Gestalt
  1216.             move.l A0,response
  1217.             move.w D0,err
  1218.             }
  1219.         #endif
  1220.         gHasCustomPutFile= err==noErr && ((short)response&1);
  1221.         }
  1222.  
  1223.     my_init();
  1224. }
  1225.  
  1226.  
  1227.  
  1228. /* conversione stringa Pascal -> intero
  1229. pascal string to integer
  1230. */
  1231. long pstrtoi(str)
  1232. Str255 str;
  1233. {
  1234. register short i=str[0];
  1235. register unsigned char *p=&str[1];
  1236. register long val=0;
  1237.  
  1238. while(i>0 && *p==' ') p++,i--;
  1239. while(i>0 && *p>='0' && *p <='9' ){
  1240.     /* val = val*10+ *p -'0'; */
  1241.     val<<=1;
  1242.     val += (val<<2) + (*p -'0');
  1243.     p++;    i--;
  1244.     }
  1245. return val;
  1246. }